<template>
	<view>
		<view class="price-list">
			<view
				class="price-list-item"
				:class="{
					checked: item.salable && !item.sold_out && checkedDate === item.date,
					disabled: !item.salable || item.sold_out,
				}"
				v-for="(item, index) in filterPrices"
				:key="index"
				@click="handlePriceClick(item)"
			>
				<view class="desc">{{ formatDateToWeek(item.date) }}</view>
				<view class="date">{{ dataToDate(item.date, 4) }}</view>
				<view class="price" v-if="item.salable && !item.sold_out">
					<view class="prefix">￥</view>
					<view class="num">{{ priceInCent(+item.price_in_cent) }}</view>
				</view>
				<image
					:src="`${imgBaseUrl}price-check-icon.png`"
					class="price-check-icon"
					v-if="item.salable && !item.sold_out && checkedDate === item.date"
				/>
				<view class="text" v-if="!item.salable || item.sold_out">不可订</view>
			</view>
			<view class="more-date" @click="showMoreDate">
				<image class="date-img" :src="`${imgBaseUrl}date.png`" />
				<view class="text">更多\n日期</view>
			</view>
		</view>
		<up-calendar
			:show="show"
			@confirm="handleConfirm"
			@close="toggleShow"
			close-on-click-overlay
			round="12"
			ref="calendar"
			:max-date="end_date"
			:month-num="monthNum"
			:default-date="checkedDate || latest_sale_date"
		></up-calendar>
	</view>
</template>

<script setup lang="ts">
import { $getTicketListPrice } from "@/api/ticket"
import { $getCombotktListPrice } from "@/api/combotkt"
import { $getTripListPrice } from "@/api/trip"
import { ref, computed, onMounted, watchEffect } from "vue"
import dayjs from "dayjs"
import type { Price } from "@/types/ticket"
import { priceInCent, dataToDate } from "@/mixins/mixins"
import { formatDateToWeek } from "@/utils/tools"

interface CalendarRef {
	setFormatter: (callback: Function) => any
}

interface PricesProps {
	/** ticket: 门票 combotkt: 联票 trip: 线路 */
	page_type: "ticket" | "combotkt" | "trip"
	prices: Price[]
	id: string
	latest_sale_date: string
	date: string
}

const props = defineProps<PricesProps>()
const emit = defineEmits(["price-change", "calendar-visible"])

// 从 prices 中过滤而来，最多展示三个
const filterPrices = ref<Price[]>([])
const checkedDate = ref("")
const show = ref(false)
const calendar = ref<CalendarRef | null>(null)
const dateList = ref<Price[]>([])
const imgBaseUrl = inject("imgBaseUrl")

const monthNum = computed(() => (dayjs().date() === 1 ? 3 : 4))
const end_date = computed(() => dayjs(props.latest_sale_date).add(90, "day").format("YYYY-MM-DD"))

const toggleShow = () => {
	show.value = !show.value

	emit("calendar-visible", show.value)
}
const handlePriceClick = (item: Price) => {
	if (item.salable && !item.sold_out) {
		checkedDate.value = item.date
		emit("price-change", { date: item.date, price_in_cent: item.price_in_cent })
	}
}

const getLatestDate = async () => {
	let list: Price[] = []

	const request = {
		ticket: $getTicketListPrice,
		combotkt: $getCombotktListPrice,
		trip: $getTripListPrice,
	}[props.page_type]

	const data = await request(props.id, props.latest_sale_date, end_date.value)

	if (props.page_type === "ticket") {
		list = (data as { list: Price[] }).list
	}

	if (props.page_type === "trip") {
		list = (data as { list: Price[] }).list
	}

	if (props.page_type === "combotkt") {
		list = (data as { prices: Price[] }).prices
	}

	return list
}

const showMoreDate = async () => {
	const list = await getLatestDate()

	dateList.value = list

	toggleShow()
}

const handleConfirm = (date: Record<string, string>) => {
	if (!date[0]) {
		toggleShow()
		return
	}

	// 先判断选中这天是否可售，因为存在都不可售的情况下，默认选中了当天
	// 如果选中这天不可售，则外面不是选中状态
	const res = dateList.value.find((item) => item.date === date[0])

	if (!res?.salable || res.sold_out) {
		toggleShow()
		return
	}

	const hasExist = filterPrices.value.some((item) => item.date === date[0])

	if (hasExist) {
		const result = filterPrices.value.find((item) => item.date === date[0])

		checkedDate.value = date[0]
		emit("price-change", { date: result!.date, price_in_cent: result!.price_in_cent })
	} else {
		const result = dateList.value.find((item) => item.date === date[0])

		if (result) {
			const firstTwoPrices = props.prices.slice(0, 2)
			filterPrices.value = [result, ...firstTwoPrices]
			checkedDate.value = result.date
			emit("price-change", { date: result.date, price_in_cent: result.price_in_cent })
		}
	}

	toggleShow()
}

const formatter = (day: { bottomInfo: string; disabled: boolean; date: Date }) => {
	if (dateList.value.length) {
		if (!dateList.value.some((item) => item.date === dayjs(day.date).format("YYYY-MM-DD"))) {
			day.disabled = true
		} else {
			dateList.value.forEach((item) => {
				if (item.date === dayjs(day.date).format("YYYY-MM-DD")) {
					const disabled = !item.salable || item.sold_out || !item.price_in_cent
					day.disabled = disabled
					day.bottomInfo = disabled ? "不可订" : `￥${priceInCent(+item.price_in_cent)}`
				}
			})
		}
	}

	return day
}

// 寻找是否有可售卖的
const findSellable = (list: Price[]) => list.find((item) => item.salable && !item.sold_out)

onMounted(async () => {
	if (calendar.value) {
		calendar.value.setFormatter(formatter)
	}
})

watchEffect(async () => {
	if (props.prices?.length) {
		// isAllNoneSellable 表示最近90天是否都不可售卖
		let item = { date: "", price_in_cent: "", isAllNoneSellable: false }

		if (props.date) {
			const res = props.prices.find((item) => item.date === props.date)

			if (res) {
				const arr = props.prices.slice(0, 3)

				if (arr.some((_item) => _item.date === props.date)) {
					filterPrices.value = arr
				} else {
					filterPrices.value = [res, ...arr.slice(0, 2)]
				}

				// 看 props.date 这天是否可售
				if (res.salable && !res.sold_out) {
					item.date = res.date
					item.price_in_cent = res.price_in_cent
				} else {
					item.date = ""
					item.price_in_cent = ""
				}
			} else {
				const list = await getLatestDate()

				// 查看最近 90 天内是否存在 props.date 这天
				const existData = list.find((item) => item.date === props.date)

				if (!existData) {
					filterPrices.value = props.prices.slice(0, 3)
					uni.showToast({ title: `${props.date}暂不可销售`, icon: "none" })
				} else {
					if (existData.salable && !existData.sold_out) {
						item.date = existData.date
						item.price_in_cent = existData.price_in_cent
						filterPrices.value = [existData, ...props.prices.slice(0, 2)]
					} else {
						item.date = ""
						item.price_in_cent = ""
						filterPrices.value = props.prices.slice(0, 3)
						uni.showToast({ title: `${props.date}暂不可销售`, icon: "none" })
					}
				}
			}
		} else {
			// 从 props.prices 中寻找是否存在可售卖的
			const result = findSellable(props.prices)

			// 如果 props.prices 中存在可售卖
			if (result) {
				item.date = result.date
				item.price_in_cent = result.price_in_cent

				const arr = props.prices.slice(0, 3)

				if (arr.some((_item) => _item.date === item.date)) {
					filterPrices.value = arr
				} else {
					filterPrices.value = [result, ...arr.slice(0, 2)]
				}
			} else {
				// 如果 props.prices 中不存在可售卖的，则需要通过接口去查询最近90天内是否存在可售卖的
				const list = await getLatestDate()

				// 最近90天内是否存在可售卖的
				const res = findSellable(list)

				if (res) {
					item.date = res.date
					item.price_in_cent = res.price_in_cent

					filterPrices.value = [res, ...props.prices.slice(0, 2)]
				} else {
					// 当 90 天内都不可售卖的情况下，date 给一个之前的值，这样的话默认值就是那天，而且不会有选中状态
					item.date = "2022-02-15"
					item.price_in_cent = props.prices[0].price_in_cent
					item.isAllNoneSellable = true
					filterPrices.value = props.prices.slice(0, 3)
					uni.showToast({ title: "暂无可销售日期", icon: "none" })
				}
			}
		}

		checkedDate.value = item.date

		if (item.isAllNoneSellable) {
			item.date = ""
		}

		emit("price-change", {
			date: item.date,
			price_in_cent: item.price_in_cent,
			isAllNoneSellable: item.isAllNoneSellable,
		})
	}
})
</script>

<style lang="scss" scoped>
.price-list {
	display: flex;
	align-items: center;

	.price-list-item {
		position: relative;
		flex: 1;
		max-width: 162rpx;
		display: flex;
		flex-direction: column;
		justify-content: center;
		align-items: center;
		padding: 16rpx 0;
		margin-right: 16rpx;
		border-radius: 16rpx;
		background: #f8f9fc;

		.desc {
			font-size: 20rpx;
			color: #1d2129;
			line-height: 28rpx;
		}

		.date {
			margin: 4rpx 0;
			font-weight: 500;
			font-size: 28rpx;
			color: #1d2129;
			line-height: 40rpx;
		}

		.price {
			display: inline-flex;
			align-items: baseline;
			color: #f53f3f;

			.prefix {
				font-weight: 500;
				font-size: 20rpx;
				line-height: 28rpx;
				margin-right: 4rpx;
			}

			.num {
				font-weight: 600;
				font-size: 28rpx;
				line-height: 40rpx;
			}
		}

		&.checked {
			border: 2rpx solid #fee038;
			background: rgba(254, 224, 56, 0.2);

			.price-check-icon {
				position: absolute;
				right: -1rpx;
				bottom: -1rpx;
				width: 24rpx;
				height: 20rpx;
			}
		}

		&.disabled {
			.desc {
				color: #c9cdd4;
			}

			.date {
				color: #c9cdd4;
			}

			.text {
				font-weight: 600;
				font-size: 28rpx;
				color: #c9cdd4;
				line-height: 40rpx;
			}
		}
	}
}

.more-date {
	display: flex;
	flex-direction: column;
	justify-content: center;
	align-items: center;
	padding: 24rpx 56rpx;
	background: #f8f9fc;
	border-radius: 16rpx;

	.date-img {
		width: 36rpx;
		height: 36rpx;
	}

	.text {
		margin-top: 8rpx;
		white-space: pre-wrap;
		font-size: 24rpx;
		color: rgba(0, 0, 0, 0.9);
		line-height: 28rpx;
	}
}
</style>
